import React, { useCallback, useContext, useEffect, useMemo, useState, useRef } from "react"
import { Row, Col, Space, Typography, Tree, Spin, Empty, message, Button, Modal, Input, Image, Pagination, Breadcrumb } from "antd"
import type { TreeDataNode, TreeProps } from "antd"
import type { InputRef } from "antd"
import { FileTextOutlined, FileImageOutlined, FilePdfOutlined, FolderFilled } from "@ant-design/icons"
import { useMobx } from "@whzhuke/mobx"
import folderService from "@/services/folder.service"
import { StoreContext } from "@/store"
import { FormRender, FormUpload } from "@whzhuke/antd"
import { functionCommon, requestCommon } from "@whzhuke/common"
import useForm from "antd/es/form/hooks/useForm"
import { Field_FormSave } from "@/components/utils/field.list"

const { Text } = Typography

// 文件接口
interface FolderFile {
  id: string
  name: string
  url: string
  type: "image" | "pdf" | "doc" | "other"
  uploadTime?: string
}

type FolderContentItem =
  | {
      kind: "folder"
      id: string
      name: string
      parentId?: string
      treeType: "1"
      sort?: number
    }
  | (FolderFile & {
      kind: "file"
      parentId?: string
      treeType: "2"
      sort?: number
    })

type FolderContentFolder = Extract<FolderContentItem, { kind: "folder" }>
type FolderContentFile = Extract<FolderContentItem, { kind: "file" }>

type FilesMapPayload = Record<string, string[]>
interface FilesPayloadItem {
  fid: string
  type: string
}
const DEFAULT_CHILD_FOLDER_NAMES = ["采购合同", "出口合同", "出货", "开票", "收汇", "付款"] as const
const DEFAULT_DIRECTORY_KEYWORDS = ["默认目录", "默认", "default"] as const
interface FilesPayloadItem {
  fid: string
  type: string
}

// 文件类型常量
const FILE_EXTENSIONS = {
  IMAGE: ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp"],
  PDF: ["pdf"],
  DOC: ["doc", "docx"],
  EXCEL: ["xls", "xlsx"]
} as const

// 获取文件类型
const getFileType = (fileName: string): FolderFile["type"] => {
  const ext = fileName.split(".").pop()?.toLowerCase() || ""
  if ((FILE_EXTENSIONS.IMAGE as readonly string[]).includes(ext)) return "image"
  if ((FILE_EXTENSIONS.PDF as readonly string[]).includes(ext)) return "pdf"
  if ((FILE_EXTENSIONS.DOC as readonly string[]).includes(ext) || (FILE_EXTENSIONS.EXCEL as readonly string[]).includes(ext)) return "doc"
  return "other"
}

// 获取文件图标
const getFileIcon = (file: FolderFile) => {
  switch (file.type) {
    case "image":
      return <FileImageOutlined style={{ fontSize: 48, color: "#1890ff" }} />
    case "pdf":
      return <FilePdfOutlined style={{ fontSize: 48, color: "#ff4d4f" }} />
    case "doc":
      return <FileTextOutlined style={{ fontSize: 48, color: "#1890ff" }} />
    default:
      return <FileTextOutlined style={{ fontSize: 48, color: "#8c8c8c" }} />
  }
}

// 样式常量
const styles = {
  container: { padding: "0 16px" },
  breadcrumb: { marginBottom: 12 },
  header: { marginBottom: 12, display: "flex", justifyContent: "space-between", alignItems: "center" },
  title: { fontSize: 16, fontWeight: 500 },
  fileContainer: {
    borderRadius: 4,
    padding: 16,
    minHeight: 200,
    marginBottom: 12,
    background: "#fff",
    display: "flex",
    flexDirection: "column" as const
  },
  fileList: {
    display: "grid",
    gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
    gap: 16
  },
  getFileCard: (isSelected: boolean) => ({
    display: "flex",
    flexDirection: "column" as const,
    alignItems: "center",
    justifyContent: "center",
    padding: 12,
    border: isSelected ? "2px solid #1890ff" : "1px solid #d9d9d9",
    borderRadius: 8,
    cursor: "pointer",
    transition: "all 0.3s",
    position: "relative" as const,
    backgroundColor: isSelected ? "#e6f7ff" : "#ffffff",
    minHeight: 150
  }),
  fileIconContainer: {
    height: 80,
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    marginBottom: 12,
    backgroundColor: "#fafafa",
    borderRadius: 8,
    border: "1px solid #e8e8e8",
    width: "100%"
  },
  fileName: {
    width: "100%",
    textAlign: "center" as const,
    fontSize: 14,
    wordBreak: "break-word" as const,
    color: "#333",
    lineHeight: "1.4",
    cursor: "pointer",
    marginTop: 8
  },
  emptyContainer: { padding: "40px 0" },
  pagination: { display: "flex", justifyContent: "flex-start", alignItems: "center", gap: 8 }
}

const buildFilesMapPayload = (items: Array<{ id?: string | number; type?: string | number }> = []): FilesMapPayload => {
  return items.reduce<FilesMapPayload>((acc, item) => {
    if (!item?.id || !item?.type) return acc
    const typeKey = String(item.type)
    const idValue = String(item.id)
    if (!acc[typeKey]) {
      acc[typeKey] = []
    }
    if (!acc[typeKey].includes(idValue)) {
      acc[typeKey].push(idValue)
    }
    return acc
  }, {})
}
const buildFilesArrayPayload = (filesMap: FilesMapPayload = {}): FilesPayloadItem[] => {
  return Object.entries(filesMap).reduce<FilesPayloadItem[]>((acc, [type, ids]) => {
    if (!Array.isArray(ids) || ids.length === 0) return acc
    ids.forEach(id => {
      const fid = String(id ?? "").trim()
      if (!fid) return
      acc.push({ fid, type })
    })
    return acc
  }, [])
}
const normalizeIdValue = (value: any): string | null => {
  if (value === undefined || value === null) return null
  if (Array.isArray(value)) {
    for (const item of value) {
      const result = normalizeIdValue(item)
      if (result) return result
    }
    return null
  }
  if (typeof value === "string" || typeof value === "number") {
    const normalized = String(value).trim()
    return normalized.length ? normalized : null
  }
  if (typeof value === "object") {
    const candidateKeys = ["id", "ID", "Id", "folderId", "folderID", "folderid", "folder_id"]
    for (const key of candidateKeys) {
      if (key in value) {
        const result = normalizeIdValue((value as any)[key])
        if (result) return result
      }
    }
  }
  return null
}
const extractFolderIdFromResponse = (response: any): string | null => {
  if (!response) return null
  const direct = normalizeIdValue(response)
  if (direct) return direct
  if (typeof response === "object") {
    const nextKeys = ["data", "result", "payload", "value"]
    for (const key of nextKeys) {
      if (key in response) {
        const nested = extractFolderIdFromResponse((response as any)[key])
        if (nested) return nested
      }
    }
  }
  return null
}

const isApiResponseSuccess = (response: any): boolean => {
  if (response === undefined || response === null) return true
  if (typeof response !== "object") return true
  if ("success" in response) {
    return Boolean(response.success)
  }
  if ("status" in response) {
    const statusCode = Number(response.status)
    if (!Number.isNaN(statusCode)) {
      return statusCode === 0 || statusCode === 200
    }
    return Boolean(response.status)
  }
  if ("code" in response) {
    const code = Number(response.code)
    if (!Number.isNaN(code)) {
      return code === 0 || code === 200
    }
    return Boolean(response.code)
  }
  return true
}

const extractApiErrorMessage = (response: any, fallback: string): string => {
  if (!response || typeof response !== "object") return fallback
  return (
    (typeof response.message === "string" && response.message) ||
    (typeof response.msg === "string" && response.msg) ||
    (typeof response.error === "string" && response.error) ||
    (typeof response.retMsg === "string" && response.retMsg) ||
    fallback
  )
}

const ensureApiSuccess = (response: any, fallback: string) => {
  if (!isApiResponseSuccess(response)) {
    throw new Error(extractApiErrorMessage(response, fallback))
  }
}

interface FolderTreeNode extends TreeDataNode {
  id?: string
  parentId?: string
  name?: string
  type?: string
  sort?: number
  url?: string
  createTs?: string | number
  children?: FolderTreeNode[]
}
const getNodeDisplayName = (node: FolderTreeNode | null): string => {
  if (!node) return ""
  if (typeof node.name === "string" && node.name.trim()) {
    return node.name.trim()
  }
  if (typeof node.title === "string" && node.title.trim()) {
    return node.title.trim()
  }
  return ""
}
const isDefaultDirectoryNode = (node: FolderTreeNode | null): boolean => {
  if (!node) return false
  const displayName = getNodeDisplayName(node)
  if (displayName && DEFAULT_DIRECTORY_KEYWORDS.some(keyword => keyword && displayName.includes(keyword))) {
    return true
  }
  const nodeId = String(node.id ?? node.key ?? "").toLowerCase()
  return nodeId === "default" || nodeId === "root" || nodeId === "0"
}

const Page = useMobx(() => {
  const { UserStore } = useContext(StoreContext)
  const [treeData, setTreeData] = useState<FolderTreeNode[]>([])
  const [loading, setLoading] = useState(false)
  const [isModalVisible, setIsModalVisible] = useState(false)
  const [folderName, setFolderName] = useState("")
  const [selectedNode, setSelectedNode] = useState<FolderTreeNode | null>(null)

  const [editingKey, setEditingKey] = useState<React.Key | null>(null)
  const [editingValue, setEditingValue] = useState("")
  const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([])
  const inputRef = useRef<InputRef>(null)

  // 文件相关状态
  const [folderContents, setFolderContents] = useState<FolderContentItem[]>([])
  const [selectedFiles, setSelectedFiles] = useState<string[]>([])
  const [currentPage, setCurrentPage] = useState(1)
  const [pageSize] = useState(16)

  // 文件编辑状态
  const [editingFileId, setEditingFileId] = useState<string | null>(null)
  const [editingFileName, setEditingFileName] = useState("")
  const fileInputRef = useRef<InputRef>(null)

  // 文件上传相关
  const [isUploadModalVisible, setIsUploadModalVisible] = useState(false)
  const [uploadForm] = useForm()
  const [uploadFolderId, setUploadFolderId] = useState<string | null>(null)

  // 文件移动相关
  const [isMoveModalVisible, setIsMoveModalVisible] = useState(false)
  const [moveTargetFolderId, setMoveTargetFolderId] = useState<string | null>(null)

  // 面包屑导航
  const [folderPath, setFolderPath] = useState<Array<{ id: string; name: string }>>([])

  const userRole = UserStore.user?.role

  const resolvedRole = useMemo(() => {
    if (userRole && typeof userRole === "string" && userRole.trim()) {
      return userRole.trim().toUpperCase()
    }
    return "ADMIN"
  }, [userRole])

  const isFolderSelected = useMemo(() => selectedNode && selectedNode.type === "1" && selectedNode.id, [selectedNode])
  const selectedFolderName = useMemo(() => {
    if (!selectedNode) return ""
    return selectedNode.name || (typeof selectedNode.title === "string" ? selectedNode.title : "")
  }, [selectedNode])
  const paginatedContents = useMemo(() => {
    const sortedContents = [...folderContents].sort((a, b) => {
      if (a.kind !== b.kind) {
        return a.kind === "folder" ? -1 : 1
      }
      return a.name.localeCompare(b.name)
    })
    const startIndex = (currentPage - 1) * pageSize
    return sortedContents.slice(startIndex, startIndex + pageSize)
  }, [folderContents, currentPage, pageSize])
  const fileItems = useMemo(() => folderContents.filter((item): item is FolderContentFile => item.kind === "file"), [folderContents])
  const selectedFileCount = selectedFiles.length
  //动态构建带权限控制的请求参数
  const buildRequestParams = useCallback(
    (params: Record<string, any> = {}) => {
      const requestParams = { ...params }
      requestParams.role = resolvedRole
      return requestParams
    },
    [resolvedRole]
  )
  const createDefaultChildFolders = useCallback(
    async (parentId: string) => {
      if (!parentId) return
      const creationTasks = DEFAULT_CHILD_FOLDER_NAMES.map((name, index) => {
        const childParams = buildRequestParams({
          name,
          parentId,
          type: "1",
          sort: index
        })
        return folderService.create(childParams)
      })
      const results = await Promise.allSettled(creationTasks)
      results.forEach((result, index) => {
        if (result.status === "rejected") {
          console.error(`自动创建子文件夹 "${DEFAULT_CHILD_FOLDER_NAMES[index]}" 失败:`, result.reason)
        }
      })
    },
    [buildRequestParams]
  )
  //树形结构函数
  const convertApiDataToTreeData = useCallback((apiData: any[]): FolderTreeNode[] => {
    if (!Array.isArray(apiData)) return []
    const mapNode = (node: any): FolderTreeNode => {
      const children = Array.isArray(node.children) ? node.children.map(mapNode) : []
      return {
        title: node.name ?? node.title ?? "未命名",
        name: node.name ?? node.title ?? "未命名",
        key: String(node.id ?? node.key ?? `${Math.random()}`),
        id: node.id,
        parentId: node.parentId,
        type: node.type ? String(node.type) : undefined,
        sort: node.sort,
        url: node.url,
        createTs: node.createTs,
        children: children.length > 0 ? children : undefined
      }
    }
    return apiData.map(mapNode)
  }, [])

  const loadFolderTree = useCallback(async () => {
    setLoading(true)
    try {
      // 调用后端接口获取目录树
      const response = await folderService.tree(buildRequestParams())
      if (response?.data) {
        setTreeData(convertApiDataToTreeData(response.data))
      } else {
        setTreeData([])
      }

      // 测试数据（已注释）
      // setTimeout(() => {
      //   setTreeData(convertApiDataToTreeData(MOCK_TREE_DATA))
      //   setLoading(false)
      // }, 300) // 模拟网络延迟
    } catch (error) {
      console.error("获取目录树失败:", error)
      message.error("获取目录树失败，请稍后重试")
    } finally {
      setLoading(false)
    }
  }, [buildRequestParams, convertApiDataToTreeData])

  useEffect(() => {
    loadFolderTree()
  }, [loadFolderTree])

  const defaultDirectoryNode = useMemo(() => {
    const findDefault = (nodes: FolderTreeNode[]): FolderTreeNode | null => {
      for (const node of nodes) {
        if (isDefaultDirectoryNode(node)) {
          return node
        }
        if (node.children) {
          const found = findDefault(node.children)
          if (found) return found
        }
      }
      return null
    }
    return findDefault(treeData)
  }, [treeData])

  // 从树数据中提取指定文件夹下的直接子文件夹与文件
  const getFolderContents = useCallback((folderId: string, data: FolderTreeNode[]): FolderContentItem[] => {
    const contents: FolderContentItem[] = []
    const normalizedFolderId = String(folderId)

    const traverse = (nodes: FolderTreeNode[]) => {
      nodes.forEach(node => {
        const nodeParentId = node.parentId !== undefined && node.parentId !== null ? String(node.parentId) : undefined
        if (nodeParentId === normalizedFolderId && node.id) {
          if (node.type === "1") {
            contents.push({
              kind: "folder",
              id: String(node.id),
              name: getNodeDisplayName(node) || "未命名",
              parentId: nodeParentId,
              treeType: "1",
              sort: node.sort
            })
          } else if (node.type === "2") {
            contents.push({
              kind: "file",
              id: String(node.id),
              name: getNodeDisplayName(node) || "未命名",
              url: node.url || "",
              type: getFileType(node.name || node.url || ""),
              uploadTime: node.createTs ? String(node.createTs) : undefined,
              parentId: nodeParentId,
              treeType: "2",
              sort: node.sort
            })
          }
        }
        if (node.children) {
          traverse(node.children)
        }
      })
    }

    traverse(data)
    return contents
  }, [])

  // 加载文件夹路径（面包屑）
  const loadFolderPath = useCallback(
    async (folderId: string) => {
      try {
        const response = await folderService.path(buildRequestParams({ id: folderId }))
        if (response?.data) {
          // 假设返回格式为：[{id: "1", name: "根目录"}, {id: "2", name: "文件夹1"}, ...]
          setFolderPath(Array.isArray(response.data) ? response.data : [])
        }
      } catch (error) {
        console.error("获取路径失败:", error)
        setFolderPath([])
      }
    },
    [buildRequestParams]
  )
  const toggleFileSelection = useCallback((fileId: string) => {
    setSelectedFiles(prev => (prev.includes(fileId) ? prev.filter(id => id !== fileId) : [...prev, fileId]))
  }, [])

  // 处理树节点选择
  const handleTreeSelect = useCallback(
    (selectedKeys: React.Key[], info: any) => {
      const node = info.node as FolderTreeNode
      setSelectedNode(node || null)

      // 如果选中的是文件夹（type=1），加载文件列表和路径
      if (node && node.type === "1" && node.id) {
        const contents = getFolderContents(node.id, treeData)
        setFolderContents(contents)
        loadFolderPath(node.id)
        setSelectedFiles([])
        setCurrentPage(1)
      } else {
        // 如果选中的不是文件夹，清空文件列表
        setFolderContents([])
        setFolderPath([])
        setSelectedFiles([])
      }
    },
    [treeData, getFolderContents, loadFolderPath]
  )

  // 当树数据变化时，如果当前选中了文件夹，更新文件列表
  useEffect(() => {
    if (selectedNode && selectedNode.type === "1" && selectedNode.id) {
      const contents = getFolderContents(selectedNode.id, treeData)
      setFolderContents(contents)
    }
  }, [treeData, selectedNode, getFolderContents])

  // 打开新建文件夹模态框
  const handleNewFolder = useCallback(() => {
    if (!selectedNode && defaultDirectoryNode) {
      setSelectedNode(defaultDirectoryNode)
      if (defaultDirectoryNode.id) {
        const contents = getFolderContents(defaultDirectoryNode.id, treeData)
        setFolderContents(contents)
        loadFolderPath(defaultDirectoryNode.id)
      } else {
        setFolderContents([])
        setFolderPath([])
      }
      if (defaultDirectoryNode.key && !expandedKeys.includes(defaultDirectoryNode.key)) {
        setExpandedKeys(prev => [...prev, defaultDirectoryNode.key!])
      }
    }
    setFolderName("")
    setIsModalVisible(true)
  }, [selectedNode, defaultDirectoryNode, getFolderContents, treeData, loadFolderPath, expandedKeys])
  const uploadFolderFileApi = useCallback(async (params: Record<string, any> = {}) => {
    const formData = new FormData()
    const appendValue = (key: string, value: any) => {
      if (value === null || value === undefined) return
      if (value instanceof Blob) {
        formData.append(key, value)
        return
      }
      if (value instanceof File) {
        formData.append(key, value)
        return
      }
      if (Array.isArray(value)) {
        value.forEach(item => appendValue(key, item))
        return
      }
      if (typeof value === "object") {
        if ("originFileObj" in value && value.originFileObj instanceof Blob) {
          formData.append(key, value.originFileObj)
          return
        }
        formData.append(key, JSON.stringify(value))
        return
      }
      formData.append(key, String(value))
    }

    Object.entries(params).forEach(([key, value]) => appendValue(key, value))

    return requestCommon.post<any>({
      url: `${functionCommon.requestHost("api")}/v1/m/sys/folder/upload/file`,
      params: formData,
      headers: { "Content-Type": "multipart/form-data;" }
    })
  }, [])

  // 递归查找节点
  const findNode = useCallback((data: FolderTreeNode[], key: React.Key): FolderTreeNode | null => {
    for (const node of data) {
      if (node.key === key) return node
      if (node.children) {
        const found = findNode(node.children, key)
        if (found) return found
      }
    }
    return null
  }, [])

  const findNodeById = useCallback((data: FolderTreeNode[], id: React.Key | undefined): FolderTreeNode | null => {
    if (id === undefined || id === null) return null
    for (const node of data) {
      if (node.id && String(node.id) === String(id)) {
        return node
      }
      if (node.children) {
        const found = findNodeById(node.children, id)
        if (found) return found
      }
    }
    return null
  }, [])

  const handleFolderItemClick = useCallback(
    (folderId: string) => {
      const node = findNodeById(treeData, folderId)
      if (!node) {
        message.warning("未找到该文件夹")
        return
      }
      const nodeKey = (node.key ?? node.id) as React.Key
      handleTreeSelect(nodeKey ? [nodeKey] : [], { node })
      setExpandedKeys(prev => {
        if (!nodeKey || prev.includes(nodeKey)) {
          return prev
        }
        return [...prev, nodeKey]
      })
    },
    [findNodeById, treeData, handleTreeSelect]
  )

  const resolveNewFolderId = useCallback(
    async (parentId: string | undefined, folderName: string) => {
      const trimmedName = folderName.trim()
      if (!trimmedName) return null
      try {
        const response = await folderService.tree(buildRequestParams())
        const treeNodes = response?.data ? convertApiDataToTreeData(response.data) : []
        const parentNode = parentId ? findNodeById(treeNodes, parentId) : null
        const candidates = parentNode?.children ?? (parentId ? [] : treeNodes)
        const matchByExact = candidates.find(child => getNodeDisplayName(child).toLowerCase() === trimmedName.toLowerCase())
        if (matchByExact?.id) {
          return String(matchByExact.id)
        }
        const matchByPartial = candidates.find(child => getNodeDisplayName(child).includes(trimmedName))
        if (matchByPartial?.id) {
          return String(matchByPartial.id)
        }
      } catch (error) {
        console.error("获取新建文件夹ID失败:", error)
      }
      return null
    },
    [buildRequestParams, convertApiDataToTreeData, findNodeById]
  )

  // 创建文件夹
  // 原则：文件夹的id是它下面子文件夹的parentId
  const handleCreateFolder = useCallback(async () => {
    const trimmedName = folderName.trim()
    if (!trimmedName) {
      message.warning("请输入文件夹名称")
      return
    }
    const parentId = selectedNode?.id || undefined
    const shouldAutoCreateDefaultChildren = isDefaultDirectoryNode(selectedNode)
    try {
      // 调用创建接口
      // 如果选中了节点，新创建的子文件夹的parentId = 选中节点的id
      const params = buildRequestParams({
        name: trimmedName,
        parentId, // 父文件夹的id作为子文件夹的parentId
        type: "1", // 1=目录
        sort: 0 // 序号，默认0
      })
      const response = await folderService.create(params)
      if (shouldAutoCreateDefaultChildren) {
        let newFolderId = extractFolderIdFromResponse(response)
        if (!newFolderId) {
          newFolderId = await resolveNewFolderId(parentId, trimmedName)
        }
        if (newFolderId) {
          await createDefaultChildFolders(newFolderId)
        } else {
          console.warn("未获取到新建文件夹ID，无法自动创建默认子文件夹", response)
        }
      }
      message.success("创建文件夹成功")
      setIsModalVisible(false)
      setFolderName("")
      setSelectedNode(null)
      // 刷新目录树
      await loadFolderTree()
    } catch (error) {
      console.error("创建文件夹失败:", error)
      message.error("创建文件夹失败，请稍后重试")
    }
  }, [folderName, selectedNode, buildRequestParams, loadFolderTree, createDefaultChildFolders, resolveNewFolderId])

  // 取消创建
  const handleCancel = useCallback(() => {
    setIsModalVisible(false)
    setFolderName("")
    setSelectedNode(null)
  }, [])

  // 删除文件夹
  const handleDeleteFolder = useCallback(async () => {
    if (!selectedNode || !selectedNode.id) {
      message.warning("请先选择一个文件夹")
      return
    }
    if (isDefaultDirectoryNode(selectedNode)) {
      message.warning("默认目录禁止删除")
      return
    }

    Modal.confirm({
      title: "确认删除",
      content: `确定要删除文件夹"${selectedNode.name || (typeof selectedNode.title === "string" ? selectedNode.title : "该文件夹")}"吗？`,
      okText: "确定",
      cancelText: "取消",
      okType: "danger",
      onOk: async () => {
        try {
          const params = buildRequestParams({ id: selectedNode.id })
          await folderService.del(params)
          message.success("删除文件夹成功")
          setSelectedNode(null)
          setFolderContents([])
          setFolderPath([])
          // 刷新目录树
          await loadFolderTree()
        } catch (error) {
          console.error("删除文件夹失败:", error)
          message.error("删除文件夹失败，请稍后重试")
        }
      }
    })
  }, [selectedNode, buildRequestParams, loadFolderTree])

  // 递归更新节点
  const updateNode = useCallback((data: FolderTreeNode[], key: React.Key, updater: (node: FolderTreeNode) => FolderTreeNode): FolderTreeNode[] => {
    return data.map(node => {
      if (node.key === key) {
        return updater(node)
      }
      if (node.children) {
        return { ...node, children: updateNode(node.children, key, updater) }
      }
      return node
    })
  }, [])

  // 双击开始编辑（仅允许目录节点）
  const handleDoubleClick = useCallback((event: React.MouseEvent, node: TreeDataNode) => {
    event.stopPropagation()
    const folderNode = node as FolderTreeNode
    if (!folderNode || folderNode.type !== "1") {
      message.info("文件名称暂不支持双击修改")
      return
    }
    const nodeTitle = typeof node.title === "string" ? node.title : String(node.title)
    setEditingKey(node.key)
    setEditingValue(nodeTitle)
  }, [])

  // 保存编辑（双击编辑后保存）
  const handleSaveEdit = useCallback(async () => {
    if (!editingKey || !editingValue.trim()) {
      setEditingKey(null)
      setEditingValue("")
      return
    }

    const node = findNode(treeData, editingKey)
    if (!node || !node.id) {
      setEditingKey(null)
      setEditingValue("")
      return
    }

    try {
      // 调用编辑接口更新文件夹名称
      // 原则：文件夹的id是它下面子文件夹的parentId
      // 编辑时只修改名称，parentId保持不变（保持层级关系）
      const params = buildRequestParams({
        id: node.id,
        name: editingValue.trim(),
        parentId: node.parentId, // 保持原有的parentId不变
        type: node.type || "1",
        sort: node.sort || 0
      })

      const response = await folderService.edit(params)
      ensureApiSuccess(response, "修改文件夹名称失败")
      message.success("修改文件夹名称成功")
      setEditingKey(null)
      setEditingValue("")
      // 刷新目录树
      await loadFolderTree()
    } catch (error) {
      console.error("修改文件夹失败:", error)
      const errorMessage = error instanceof Error ? error.message : "修改文件夹失败，请稍后重试"
      message.error(errorMessage)
    }
  }, [editingKey, editingValue, treeData, findNode, buildRequestParams, loadFolderTree])

  // 取消编辑
  const handleCancelEdit = useCallback(() => {
    setEditingKey(null)
    setEditingValue("")
  }, [])

  // 自动聚焦输入框
  useEffect(() => {
    if (editingKey) {
      setTimeout(() => {
        inputRef.current?.focus()
        inputRef.current?.select()
      }, 100)
    }
  }, [editingKey])

  // 自动聚焦文件重命名输入框
  useEffect(() => {
    if (editingFileId) {
      setTimeout(() => {
        fileInputRef.current?.focus()
        fileInputRef.current?.select()
      }, 100)
    }
  }, [editingFileId])

  // 处理拖拽
  const onDragEnter: TreeProps["onDragEnter"] = useCallback(info => {
    setExpandedKeys(info.expandedKeys)
  }, [])

  const onDrop: TreeProps["onDrop"] = useCallback(
    async info => {
      const dropKey = info.node.key
      const dragKey = info.dragNode.key

      if (dropKey === dragKey) {
        return
      }

      const dragNode = findNode(treeData, dragKey) as FolderTreeNode
      const dropNode = findNode(treeData, dropKey) as FolderTreeNode

      if (!dragNode || !dragNode.id || !dropNode || !dropNode.id) {
        message.warning("移动失败，节点信息不完整")
        return
      }

      // 检查是否拖到自己的子节点中（防止循环引用）
      const isDescendant = (parentKey: React.Key, childKey: React.Key, data: FolderTreeNode[]): boolean => {
        const parent = findNode(data, parentKey)
        if (!parent || !parent.children) return false
        for (const child of parent.children) {
          if (child.key === childKey) return true
          if (child.children && isDescendant(child.key, childKey, data)) return true
        }
        return false
      }

      if (isDescendant(dragKey, dropKey, treeData)) {
        message.warning("不能将文件夹移动到自己的子文件夹中")
        return
      }

      try {
        const filesPayloadMap = buildFilesMapPayload([{ id: dragNode.id, type: "1" }])
        const filesPayload = buildFilesArrayPayload(filesPayloadMap)
        // 调用移动接口：type=1 表示目录移动，fid 仅传一个目录ID
        const params = buildRequestParams({
          files: filesPayload,
          fid: String(dragNode.id),
          type: "1",
          targetFolderId: dropNode.id
        })

        const response = await folderService.move(params)
        ensureApiSuccess(response, "移动目录失败")
        message.success("移动文件夹成功")
        // 刷新目录树
        await loadFolderTree()
      } catch (error) {
        console.error("移动文件夹失败:", error)
        const errorMessage = error instanceof Error ? error.message : "移动文件夹失败，请稍后重试"
        message.error(errorMessage)
      }
    },
    [treeData, findNode, buildRequestParams, loadFolderTree]
  )

  // 处理树数据，添加编辑功能和拖拽
  const processedTreeData = useMemo(() => {
    const processNodes = (nodes: FolderTreeNode[]): FolderTreeNode[] => {
      return nodes.map(node => {
        const nodeTitle = typeof node.title === "string" ? node.title : String(node.title)
        const isEditing = editingKey === node.key

        const renderDot = node.type === "2" && !isEditing
        return {
          ...node,
          title: isEditing ? (
            <Input
              ref={inputRef}
              value={editingValue}
              onChange={e => setEditingValue(e.target.value)}
              onBlur={handleSaveEdit}
              onKeyDown={e => {
                if (e.key === "Enter") {
                  handleSaveEdit()
                } else if (e.key === "Escape") {
                  handleCancelEdit()
                }
              }}
              onClick={e => e.stopPropagation()}
              style={{ width: "auto", minWidth: 100 }}
              size="small"
            />
          ) : (
            <span
              onDoubleClick={e => handleDoubleClick(e, node)}
              style={{ padding: "2px 4px", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 6 }}
            >
              {renderDot ? <span style={{ width: 4, height: 4, borderRadius: "50%", backgroundColor: "#000" }} /> : null}
              {nodeTitle}
            </span>
          ),
          children: node.children ? processNodes(node.children) : undefined
        }
      })
    }
    return processNodes(treeData)
  }, [treeData, editingKey, editingValue, handleSaveEdit, handleCancelEdit, handleDoubleClick])

  const treeContent = useMemo(() => {
    if (loading) {
      return (
        <div style={{ minHeight: 200, display: "flex", alignItems: "center", justifyContent: "center" }}>
          <Spin />
        </div>
      )
    }
    if (!treeData.length) {
      return <Empty description="暂无目录数据" image={Empty.PRESENTED_IMAGE_SIMPLE} />
    }
    return (
      <Tree
        className="folder-tree"
        defaultExpandAll
        treeData={processedTreeData}
        onSelect={handleTreeSelect}
        draggable={{
          icon: false,
          nodeDraggable: node => (node as FolderTreeNode)?.type === "1"
        }}
        allowDrop={({ dropNode }) => (dropNode as FolderTreeNode)?.type === "1"}
        onDragEnter={onDragEnter}
        onDrop={onDrop}
        expandedKeys={expandedKeys}
        onExpand={setExpandedKeys}
      />
    )
  }, [loading, treeData, processedTreeData, handleTreeSelect, onDragEnter, onDrop, expandedKeys])

  return (
    <>
      <style>{`
        .folder-tree .ant-tree-switcher-noop {
          display: none !important;
        }
        .folder-tree .ant-tree-iconEle,
        .folder-tree .ant-tree-draggable-icon,
        .folder-tree .anticon-holder {
          display: none !important;
        }
      `}</style>
      <Row>
        <Col span={6} style={{ borderRight: "1px solid #d9d9d9", paddingRight: 16 }}>
          <Space direction="vertical" style={{ width: "100%" }} size="middle">
            <Space>
              <Text strong>文件夹列表</Text>
              <Button type="primary" size="small" onClick={handleNewFolder}>
                新建
              </Button>
              <Button danger size="small" onClick={handleDeleteFolder} disabled={!selectedNode}>
                删除
              </Button>
            </Space>
            <Text type="secondary" style={{ fontSize: 12 }}>
              当前角色：{resolvedRole}
              {isFolderSelected && ` | 已选中：${selectedFolderName || "节点"}`}
            </Text>
            <div style={{ borderRadius: 4, padding: 8, minHeight: 400, maxHeight: 600, overflowY: "auto" }}>{treeContent}</div>
          </Space>
        </Col>
        <Col span={18}>
          <div style={styles.container}>
            {/* 面包屑导航 */}
            {folderPath.length > 0 && (
              <Breadcrumb style={styles.breadcrumb}>
                {folderPath.map((item, index) => (
                  <Breadcrumb.Item key={item.id}>{index === folderPath.length - 1 ? <Text strong>{item.name}</Text> : item.name}</Breadcrumb.Item>
                ))}
              </Breadcrumb>
            )}

            {/* 标题和操作按钮区域 */}
            <div style={styles.header}>
              <div>
                <span style={styles.title}>{isFolderSelected ? `文件夹：${selectedFolderName || "未知"}` : "请选择一个文件夹查看文件"}</span>
              </div>
              {isFolderSelected ? (
                <Space>
                  <Button
                    size="small"
                    type="primary"
                    disabled={selectedFileCount === 0}
                    onClick={() => {
                      if (selectedFileCount === 0) {
                        message.warning("请先选择要移动的文件")
                        return
                      }
                      setIsMoveModalVisible(true)
                      setMoveTargetFolderId(null)
                    }}
                  >
                    移动
                  </Button>
                  <Button
                    size="small"
                    type="primary"
                    disabled={selectedFileCount === 0}
                    onClick={() => {
                      if (selectedFileCount === 0) {
                        message.warning("请先选择要下载的文件")
                        return
                      }
                      selectedFiles.forEach(fileId => {
                        const file = fileItems.find(f => f.id === fileId)
                        if (file) {
                          const url = functionCommon.replaceHost(file.url, "public" as any)
                          window.open(url, "_blank")
                        }
                      })
                    }}
                  >
                    下载
                  </Button>
                  <Button
                    size="small"
                    danger
                    disabled={selectedFileCount === 0}
                    onClick={() => {
                      if (selectedFileCount === 0) {
                        message.warning("请先选择要删除的文件")
                        return
                      }
                      Modal.confirm({
                        title: "确认删除",
                        content: `确定要删除选中的 ${selectedFiles.length} 个文件吗？`,
                        okText: "确定",
                        cancelText: "取消",
                        okType: "danger",
                        onOk: async () => {
                          try {
                            // 批量删除文件
                            const deletePromises = selectedFiles.map(fileId => folderService.del(buildRequestParams({ id: fileId })))
                            await Promise.all(deletePromises)
                            message.success(`已成功删除 ${selectedFiles.length} 个文件`)
                            setSelectedFiles([])
                            // 刷新目录树
                            await loadFolderTree()
                          } catch (error) {
                            console.error("删除文件失败:", error)
                            message.error("删除文件失败，请稍后重试")
                          }
                        }
                      })
                    }}
                  >
                    删除
                  </Button>
                  <Button
                    type="primary"
                    size="small"
                    onClick={() => {
                      if (!isFolderSelected || !selectedNode?.id) {
                        message.warning("请先选择一个文件夹")
                        return
                      }
                      setUploadFolderId(selectedNode.id)
                      setIsUploadModalVisible(true)
                      uploadForm.resetFields()
                    }}
                  >
                    上传
                  </Button>
                </Space>
              ) : null}
            </div>

            {/* 文件显示区域 */}
            <div style={styles.fileContainer}>
              {folderContents.length === 0 ? (
                <Empty
                  description={isFolderSelected ? "该文件夹暂无内容" : "请选择一个文件夹"}
                  image={Empty.PRESENTED_IMAGE_SIMPLE}
                  style={styles.emptyContainer}
                />
              ) : (
                <div style={{ ...styles.fileList, flexGrow: 1 }}>
                  {paginatedContents.map(item => {
                    if (item.kind === "folder") {
                      const isActiveFolder = selectedNode?.id && String(selectedNode.id) === item.id
                      return (
                        <div
                          key={`folder-${item.id}`}
                          style={styles.getFileCard(Boolean(isActiveFolder))}
                          onClick={e => {
                            e.stopPropagation()
                            handleFolderItemClick(item.id)
                          }}
                        >
                          <div style={styles.fileIconContainer}>
                            <FolderFilled style={{ fontSize: 48, color: "#faad14" }} />
                          </div>
                          <div style={styles.fileName} title={item.name}>
                            {item.name}
                          </div>
                        </div>
                      )
                    }

                    const file = item
                    const isSelected = selectedFiles.includes(file.id)
                    return (
                      <div
                        key={file.id}
                        style={styles.getFileCard(isSelected)}
                        onClick={() => {
                          if (editingFileId !== file.id) {
                            toggleFileSelection(file.id)
                          }
                        }}
                        onDoubleClick={e => {
                          e.stopPropagation()
                          message.info("文件名称暂不支持双击修改")
                        }}
                      >
                        <div
                          style={styles.fileIconContainer}
                          onDoubleClick={e => {
                            e.stopPropagation()
                            message.info("文件名称暂不支持双击修改")
                          }}
                        >
                          {file.type === "image" ? (
                            <Image
                              src={functionCommon.replaceHost(file.url, "public" as any)}
                              alt={file.name}
                              width={80}
                              height={80}
                              style={{ objectFit: "cover", borderRadius: 8 }}
                              preview={false}
                            />
                          ) : (
                            getFileIcon(file)
                          )}
                        </div>
                        {editingFileId === file.id ? (
                          <Input
                            ref={fileInputRef}
                            value={editingFileName}
                            onChange={e => setEditingFileName(e.target.value)}
                            onBlur={async () => {
                              if (editingFileId && editingFileName.trim()) {
                                try {
                                  const fileNode = findNodeById(treeData, editingFileId)
                                  if (fileNode) {
                                    const params = buildRequestParams({
                                      id: fileNode.id,
                                      name: editingFileName.trim(),
                                      parentId: fileNode.parentId,
                                      type: "2",
                                      sort: fileNode.sort || 0
                                    })
                                    const response = await folderService.edit(params)
                                    ensureApiSuccess(response, "修改文件名失败")
                                    message.success("修改文件名成功")
                                    await loadFolderTree()
                                  }
                                } catch (error) {
                                  console.error("修改文件名失败:", error)
                                  const errorMessage = error instanceof Error ? error.message : "修改文件名失败，请稍后重试"
                                  message.error(errorMessage)
                                }
                              }
                              setEditingFileId(null)
                              setEditingFileName("")
                            }}
                            onKeyDown={e => {
                              if (e.key === "Enter") {
                                e.currentTarget.blur()
                              } else if (e.key === "Escape") {
                                setEditingFileId(null)
                                setEditingFileName("")
                              }
                            }}
                            onClick={e => e.stopPropagation()}
                            style={{ width: "100%", fontSize: 12, textAlign: "center" }}
                            size="small"
                          />
                        ) : (
                          <div
                            style={styles.fileName}
                            title={file.name}
                            onDoubleClick={e => {
                              e.stopPropagation()
                              message.info("文件名称暂不支持双击修改")
                            }}
                          >
                            {file.name}
                          </div>
                        )}
                      </div>
                    )
                  })}
                </div>
              )}
            </div>

            {/* 分页控件 */}
            {folderContents.length > 0 && (
              <div style={{ ...styles.pagination, justifyContent: "center", marginTop: "auto" }}>
                <Pagination current={currentPage} total={folderContents.length} pageSize={pageSize} onChange={setCurrentPage} />
              </div>
            )}
          </div>
        </Col>

        {/* 新建文件夹模态框 */}
        <Modal title="新建文件夹" open={isModalVisible} onOk={handleCreateFolder} onCancel={handleCancel} okText="确定" cancelText="取消">
          <Input value={folderName} onChange={e => setFolderName(e.target.value)} placeholder="请输入文件夹名称" onPressEnter={handleCreateFolder} autoFocus />
          {isFolderSelected && (
            <Text type="secondary" style={{ display: "block", marginTop: 8, fontSize: 12 }}>
              将在"{selectedFolderName || "选中节点"}"下创建子文件夹
            </Text>
          )}
        </Modal>

        {/* 上传文件模态框 */}
        <Modal
          title="上传文件"
          open={isUploadModalVisible}
          onCancel={() => {
            setIsUploadModalVisible(false)
            uploadForm.resetFields()
          }}
          footer={null}
          width={600}
        >
          <FormRender
            form={uploadForm}
            layout="horizontal"
            preserve={false}
            onFinish={async (data: any) => {
              const { file } = data
              if (!file || (Array.isArray(file) && file.length === 0) || (typeof file === "string" && !file)) {
                message.warning("请选择要上传的文件")
                return
              }

              if (!uploadFolderId) {
                message.warning("请先选择一个文件夹")
                return
              }

              try {
                // FormUpload 组件会自动上传文件，file 是 URL 字符串或 URL 字符串数组
                const fileUrls = Array.isArray(file) ? file : [file]

                // 为每个文件调用上传接口创建文件记录
                const uploadPromises = fileUrls.map(async (fileUrl: string) => {
                  if (!fileUrl || typeof fileUrl !== "string") {
                    console.warn("文件URL无效:", fileUrl)
                    return null
                  }

                  // 从 URL 中提取文件名
                  const urlParts = fileUrl.split("/")
                  const fileName = urlParts[urlParts.length - 1] || `文件${Date.now()}`

                  // 调用上传接口创建文件记录
                  // 注意：这里需要确认后端接口是否支持通过 folderId 和 url 创建文件记录
                  // 如果后端需要先上传文件再创建记录，可能需要调整
                  const params = buildRequestParams({
                    folderId: uploadFolderId,
                    url: fileUrl,
                    name: fileName,
                    type: "2", // 文件类型
                    sort: 0
                  })

                  // 如果后端有专门的创建文件接口，使用 create；否则可能需要其他方式
                  // 这里假设可以通过 create 接口创建文件记录
                  await folderService.create(params)
                  return fileUrl
                })

                await Promise.all(uploadPromises.filter(p => p !== null))

                message.success(`已成功上传 ${fileUrls.length} 个文件`)
                setIsUploadModalVisible(false)
                uploadForm.resetFields()

                // 刷新目录树
                await loadFolderTree()
              } catch (error) {
                console.error("文件上传失败:", error)
                message.error("文件上传失败，请重试")
              }
            }}
            labelCol={{ span: 8 }}
            wrapperCol={{ span: 16 }}
            fieldList={[
              {
                fieldType: "diy",
                formItemConfig: {
                  name: "file",
                  label: "文件",
                  required: true,
                  rules: [{ required: true, message: "请上传文件" }]
                },
                component: (
                  <FormUpload apiService={uploadFolderFileApi} maxCount={10} resKey="url" apiParams={buildRequestParams({ folderId: uploadFolderId })} />
                )
              },
              { ...Field_FormSave, formItemConfig: { wrapperCol: { offset: 8, span: 16 } } }
            ]}
            autoComplete="off"
          />
        </Modal>

        {/* 移动文件模态框 */}
        <Modal
          title="移动文件"
          open={isMoveModalVisible}
          onOk={async () => {
            if (!moveTargetFolderId) {
              message.warning("请选择目标文件夹")
              return
            }
            if (selectedFiles.length === 0) {
              message.warning("请先选择要移动的文件")
              return
            }

            try {
              // 调用移动接口
              const fileIds = selectedFiles.filter(Boolean).join(",")
              if (!fileIds) {
                message.warning("未获取到有效的文件ID")
                return
              }
              const filesPayloadMap = buildFilesMapPayload(selectedFiles.map(id => ({ id, type: "2" })))
              const filesPayload = buildFilesArrayPayload(filesPayloadMap)
              const params = buildRequestParams({
                files: filesPayload,
                fid: fileIds, // 文件ID使用逗号拼接成字符串
                type: "2", // 文件类型
                targetFolderId: moveTargetFolderId // 目标目录ID
              })

              const response = await folderService.move(params)
              ensureApiSuccess(response, "移动文件失败")
              message.success(`已成功移动 ${selectedFiles.length} 个文件`)
              setIsMoveModalVisible(false)
              setMoveTargetFolderId(null)
              setSelectedFiles([])
              // 刷新目录树
              await loadFolderTree()
            } catch (error) {
              console.error("移动文件失败:", error)
              const errorMessage = error instanceof Error ? error.message : "移动文件失败，请稍后重试"
              message.error(errorMessage)
            }
          }}
          onCancel={() => {
            setIsMoveModalVisible(false)
            setMoveTargetFolderId(null)
          }}
          okText="确定"
          cancelText="取消"
          width={500}
        >
          <Text type="secondary" style={{ display: "block", marginBottom: 16 }}>
            请选择目标文件夹，将把选中的 {selectedFiles.length} 个文件移动到目标文件夹
          </Text>
          <div style={{ border: "1px solid #d9d9d9", borderRadius: 4, padding: 8, maxHeight: 400, overflowY: "auto" }}>
            <Tree
              className="folder-tree"
              treeData={processedTreeData}
              onSelect={selectedKeys => {
                if (selectedKeys.length > 0) {
                  const selectedKey = selectedKeys[0]
                  const node = findNode(treeData, selectedKey)
                  if (node && node.type === "1" && node.id) {
                    setMoveTargetFolderId(node.id)
                  }
                }
              }}
              defaultExpandAll
            />
          </div>
        </Modal>
      </Row>
    </>
  )
})

export default Page
